<!DOCTYPE html>
<html>
<head>
<title>sdp中商品流转过程</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* GitHub stylesheet for MarkdownPad (http://markdownpad.com) */
/* Author: Nicolas Hery - http://nicolashery.com */
/* Version: b13fe65ca28d2e568c6ed5d7f06581183df8f2ff */
/* Source: https://github.com/nicolahery/markdownpad-github */

/* RESET
=============================================================================*/

html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
}

/* BODY
=============================================================================*/

body {
  font-family: Helvetica, arial, freesans, clean, sans-serif;
  font-size: 14px;
  line-height: 1.6;
  color: #333;
  background-color: #fff;
  padding: 20px;
  max-width: 960px;
  margin: 0 auto;
}

body>*:first-child {
  margin-top: 0 !important;
}

body>*:last-child {
  margin-bottom: 0 !important;
}

/* BLOCKS
=============================================================================*/

p, blockquote, ul, ol, dl, table, pre {
  margin: 15px 0;
}

/* HEADERS
=============================================================================*/

h1, h2, h3, h4, h5, h6 {
  margin: 20px 0 10px;
  padding: 0;
  font-weight: bold;
  -webkit-font-smoothing: antialiased;
}

h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
  font-size: inherit;
}

h1 {
  font-size: 28px;
  color: #000;
}

h2 {
  font-size: 24px;
  border-bottom: 1px solid #ccc;
  color: #000;
}

h3 {
  font-size: 18px;
}

h4 {
  font-size: 16px;
}

h5 {
  font-size: 14px;
}

h6 {
  color: #777;
  font-size: 14px;
}

body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
  margin-top: 0;
  padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
  margin-top: 0;
  padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
  margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
  color: #4183C4;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
  padding-left: 30px;
}

ul li > :first-child, 
ol li > :first-child, 
ul li ul:first-of-type, 
ol li ol:first-of-type, 
ul li ol:first-of-type, 
ol li ul:first-of-type {
  margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
  margin-bottom: 0;
}

dl {
  padding: 0;
}

dl dt {
  font-size: 14px;
  font-weight: bold;
  font-style: italic;
  padding: 0;
  margin: 15px 0 5px;
}

dl dt:first-child {
  padding: 0;
}

dl dt>:first-child {
  margin-top: 0px;
}

dl dt>:last-child {
  margin-bottom: 0px;
}

dl dd {
  margin: 0 0 15px;
  padding: 0 15px;
}

dl dd>:first-child {
  margin-top: 0px;
}

dl dd>:last-child {
  margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
  font-size: 12px;
  font-family: Consolas, "Liberation Mono", Courier, monospace;
}

code, tt {
  margin: 0 0px;
  padding: 0px 0px;
  white-space: nowrap;
  border: 1px solid #eaeaea;
  background-color: #f8f8f8;
  border-radius: 3px;
}

pre>code {
  margin: 0;
  padding: 0;
  white-space: pre;
  border: none;
  background: transparent;
}

pre {
  background-color: #f8f8f8;
  border: 1px solid #ccc;
  font-size: 13px;
  line-height: 19px;
  overflow: auto;
  padding: 6px 10px;
  border-radius: 3px;
}

pre code, pre tt {
  background-color: transparent;
  border: none;
}

kbd {
    -moz-border-bottom-colors: none;
    -moz-border-left-colors: none;
    -moz-border-right-colors: none;
    -moz-border-top-colors: none;
    background-color: #DDDDDD;
    background-image: linear-gradient(#F1F1F1, #DDDDDD);
    background-repeat: repeat-x;
    border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
    border-image: none;
    border-radius: 2px 2px 2px 2px;
    border-style: solid;
    border-width: 1px;
    font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
    line-height: 10px;
    padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
  border-left: 4px solid #DDD;
  padding: 0 15px;
  color: #777;
}

blockquote>:first-child {
  margin-top: 0px;
}

blockquote>:last-child {
  margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
  clear: both;
  margin: 15px 0;
  height: 0px;
  overflow: hidden;
  border: none;
  background: transparent;
  border-bottom: 4px solid #ddd;
  padding: 0;
}

/* TABLES
=============================================================================*/

table th {
  font-weight: bold;
}

table th, table td {
  border: 1px solid #ccc;
  padding: 6px 13px;
}

table tr {
  border-top: 1px solid #ccc;
  background-color: #fff;
}

table tr:nth-child(2n) {
  background-color: #f8f8f8;
}

/* IMAGES
=============================================================================*/

img {
  max-width: 100%
}
</style>
</head>
<body>
<h1>sdp中商品流转过程</h1>
<ul>
<li>
<h3>商品发布</h3>
<ol>
<li>
<p>新建发布配置，填写配置信息和商品信息</p>
<pre><code>发布配置中填写的配置信息包括：配置名称，包含的产品配置。
商品信息包括：商品标识，商品标题，商品描述，商品标签，是否公开，商品图片等
其中，商品标识会经过store进行校验是否已被占用
商品一经发布，商品标识、商品标题即处于锁定状态，不能再修改
</code></pre>

</li>
<li>
<p>填写版本信息，选择商品文件</p>
<pre><code>商品发布前，需要填写版本信息，包括版本类型（稳定版/快照版），产品文件（哪一次的构建结果），版本号，版本简介
其中版本号需要经过store校验是否已经存在      
商品文件即构建结果，从“使用了该发布配置中产品配置的构建配置的构建结果”中选取 
</code></pre>

</li>
<li>
<p>发布过程</p>
<pre><code>Ⅰ. 获取发布信息和商品信息
Ⅱ. 添加发布信息（sdp中通过publish表记录发布历史）
Ⅲ. 向store发请求，创建商品版本
Ⅳ. 上传商品文档（如果有文档的话）
Ⅴ. 通知store文件上传完毕
Ⅵ. 准备商品文件。不同类型的商品对商品文件的处理方式不同，（详见“产品支持文档”）
Ⅶ. 上传商品文件
Ⅷ. 通知store文件上传完毕
Ⅸ. 通知store商品发布完成

发布过程中如果出现错误，例如：文档上传失败，或者商品文件上传失败，会向store请求删除之前创建的版本
</code></pre>

</li>
</ol>
</li>
<li>
<h3>本地仓库的使用</h3>
<p>本地仓库的目的是缓存商品，当用户使用store中的商品时（例如：移动应用构建时使用了移动插件），sdp.server会首先检查本地仓库中是否已经存在该商品，如果有则直接使用，如果没有则从store中下载商品文件，存放在本地仓库中。enzyme.agent中同样存在本地仓库，在更新工作空间中依赖时发挥作用。</p>
<h4>本地仓库接口说明</h4>
<ol>
<li>
<blockquote>
<p>检查本地仓库目录下local_store.xml文件是否存在，如果不存在则创建出来。</p>
<p>checkLocalStoreXmlExistSync（）</p>
</blockquote>
<p>本地仓库中缓存的商品记录在local_store.xml文件中，文件结构如下：</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;yes&quot;?&gt;
&lt;goods&gt;
  &lt;local_goods fileName=&quot;core_java&quot; version=&quot;2.1.0&quot; qualifier=&quot;20161119121502329&quot;/&gt;
  &lt;local_goods fileName=&quot;test_plugin&quot; version=&quot;2.2.5&quot; qualifier=&quot;20161213174956107&quot;/&gt;
&lt;/goods&gt;
</code></pre>

<p>其中商品信息包括fileName(商品名)，version(商品版本号)，qualifier(版本时间戳)。</p>
</li>
<li>
<blockquote>
<p>获取本地仓库所有商品信息</p>
<p>getAllLocalGoods(callback)</p>
</blockquote>
</li>
<li>
<blockquote>
<p>检查本地仓库中是否存在某商品</p>
<p>isFileExist(fileName, version, qualifier,callback)</p>
</blockquote>
<pre><code>根据商品名，版本号，时间戳检查某商品对应的版本是否存在（如果是快照版，则根据时间戳判断是否为最新快照）
</code></pre>

</li>
<li>
<blockquote>
<p>本地仓库中添加新的商品</p>
<p>addLocalGoods(goods_info, callback)</p>
</blockquote>
<pre><code>当用户使用了本地仓库中没有商品时，需要调用该接口从store中下载商品，并在本地仓库中缓存下来
goods_info中包含信息：
    {
        fileName : 商品名
        version： 商品版本号
        type： 商品类型
        version_type： 版本类型（stable/snapshot）
        qualifier: 时间戳
    }
</code></pre>

<p>项目依赖的商品会在用户使用时下载到本地仓库中缓存，有两种场景会触发下载操作：	</p>
<ul>
<li>
<p>更新工作空间时</p>
</li>
<li>
<p>产品构建检查依赖时</p>
</li>
</ul>
<p>下载商品时，在本地仓库中创建以  <code>&quot;商品标识&quot; + &quot;_&quot; + &quot;版本号&quot;</code>（快照版为：<code>&quot;商品标识&quot; + &quot;_&quot; + &quot;版本号&quot; + &quot;时间戳&quot;</code>）命名的文件夹，然后将下载到的商品解压到文件夹中，这个过程对不同类型的产品有不同的处理：</p>
<ul>
<li>
<p>移动插件产品</p>
<pre><code>第一次解压后，遍历解压后的目录，然后再次解压目录下的压缩包
</code></pre>

</li>
<li>
<p>其他类型产品</p>
<pre><code>直接将商品解压即可                   
</code></pre>

</li>
</ul>
</li>
</ol>
</li>
<li>
<h3>项目依赖处理</h3>
<h4>项目中依赖添加、管理、使用规则</h4>
<ol>
<li>
<p>项目依赖列表管理</p>
<p>项目依赖是指项目中使用到的商品（一般是插件类型），在“项目管理 -&gt; 项目信息 -&gt; 项目依赖信息”下可看到项目依赖列表。
项目依赖列表包含以下信息：	</p>
<p>依赖标题、依赖添加者、依赖状态</p>
<p>依赖管理需要有项目管理员权限，管理员可以对任何项目依赖（不管是否是自己添加的）进行操作（删除、更新），可以将自己已购买的商品添加到项目依赖列表中。</p>
</li>
<li>
<p>依赖状态计算</p>
<p>项目依赖的状态有：正常、有新版本、商品未购买</p>
<pre><code>正常状态： 商品已购买（相对于依赖添加者而言），且是最新版本
有新版本： 商品已购买（相对于依赖添加者而言），但是非最新版本。
商品未购买：  商品未购买（相对于依赖添加者而言）   
</code></pre>

<p>用户进入sdp，在项目信息中查看项目依赖信息时会对依赖的状态进行计算：</p>
<p>假设某项目依赖列表为：</p>
<pre><code>依赖插件A1 user1
依赖插件A2 user1
依赖插件B  user2
依赖插件C  user3 
</code></pre>

<p>首先遍历依赖列表，按依赖的添加者对依赖进行分组，得到一个json：</p>
<pre><code>dependencies:{
        user1 :[
            pluginA1:{//插件A1信息}，
            pluginA2:{//插件A2信息}，
        ]，
        user2 :[
            pluginB:{//插件B信息}，
        ]
        user3 :[
            pluginC:{//插件C信息}，
        ]
}
</code></pre>

<p>然后遍历dependencies，向store中请求，分别获取user1、user2、user3的购买列表orderList
分别遍历dependencies.user1，dependencies.user2，dependencies.user3，将这些依赖项和user1、user2、user3的orderList对比：</p>
<p>依赖项不在orderList中，则依赖状态为“商品未购买”，标记为0</p>
<p>依赖项存在，获取orderList中的最近版本latest<em>version，如果依赖项为稳定版，对比依赖和latest</em>version的版本号，如果不一致则依赖状态为“有新版本”，标记为“2”；如果依赖项为快照版，对比依赖和latest_version的版本号和时间戳，如果不一致则依赖状态为“有新版本”，标记为“2”</p>
<p>依赖项存在，且为最新版本，则状态正常，标记为“1”</p>
</li>
<li>
<p>构建时，依赖状态判断</p>
<p>在构建时，需要判断待构建工程中使用到的依赖项状态。以移动应用构建为例：</p>
<p>发起构建前需要准备依赖的插件，解析移动工程中的carrier.config，获得移动工程用到的插件列表，然后遍历插件列表，向store发送请求，查询用户对插件使用情况（这里的查询方接口不同于2），如果某插件用户不可用，或store中已经删除或下架了某插件，则构建发起失败。</p>
</li>
<li>
<p>更新工作空间中依赖</p>
<p>工作空间中以target的形式使用以来。
通过调用enzyme.agent中的接口完成依赖更新。目前不支持局部更新。更新过程如下：</p>
<ul>
<li>
<p>从项目依赖列表project_dependencies中删除状态为0的依赖项（即删除已经失效的依赖）</p>
</li>
<li>
<p>检查各个依赖项对应的商品文件在本地仓库中是否存在，如果不存在，则下载。</p>
</li>
<li>
<p>所有依赖项对应的商品文件都已经存在后，检查workspace中target目录，eme目录，plugins目录是否存在，如果存在，则删除后重新创建。如果不存在，创建出来。</p>
</li>
<li>
<p>目录处理完毕后，遍历项目依赖，根据商品类型分别处理，将商品文件以软链接的形式添加到工作空间中。</p>
<pre><code>core_java类型： (假设依赖的商品为core_java_v2.0.0)
    将本地仓库中core_java_v2.0.0目录下的所有文件（夹）链接到 工作空间目录/target/core/java 下。

core_node类型： (假设依赖的商品为core_frontend_5.1.0)
    将本地仓库中core_frontend_5.1.0目录下的所有文件（夹）链接到 工作空间目录/target/core/node 下。

app_plugin类型：（假设依赖的商品为test_app_plugin_1.0.0）
    将本地仓库中core_frontend_5.1.0目录下的所有文件（夹）链接到 工作空间目录/target/nectar_plugin 下
    然后在 工作空间目录/target/nectar_plugin 下创建plugin.json文件用来记录插件信息。包括以下信息：
        name: 插件标识
        version: 插件版本,
        dir: 文件文件名,
        plugin_name: 插件名称,
        qualifier: 插件时间戳,
        version_type: 插件版本类型,
        introduction: 插件介绍
    在开发nectar时，enzyme会从该文件中读取所有用户可用的插件

enzyme_eme：（假设依赖的商品为test_enzyme_eme_1.0.0）
    将本地仓库中core_frontend_5.1.0目录下的所有文件（夹）链接到 工作空间目录/eme/product 下

enzyme_plugin类型：（假设依赖的商品为test_enzyme_plugin_1.0.0）
    将本地仓库中core_frontend_5.1.0目录下的所有文件（夹）链接到 工作空间目录/plugins 下

mk_feature类型:
    目前没有对mk_feature类型依赖的使用需求，以前的处理不适合现在对mk的规划，需要改变处理过程
</code></pre>

</li>
</ul>
</li>
</ol>
</li>
</ul>

</body>
</html>
<!-- This document was created with MarkdownPad, the Markdown editor for Windows (http://markdownpad.com) -->
